home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
Other Langs
/
Tickle-4.0 (tcl)
/
src
/
tar_buffer.c
< prev
next >
Wrap
Text File
|
1993-11-07
|
8KB
|
374 lines
#pragma segment TAR
/*
* Macintosh Tar
*
* Modified by Craig Ruff for use on the Macintosh.
*/
/*
* Buffer management for public domain tar.
*
* Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
*
* @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
*
*/
#include "tar.h"
Boolean FlushArchive();
union record *arBlock; /* Start of block of archive */
union record *arRecord; /* Current record of archive */
union record *arLast; /* Last+1 record of archive block */
char arReading; /* 0 writing, !0 reading archive */
/*
* The record pointed to by save_rec should not be overlaid
* when reading in a new tape block. Copy it to record_save_area first, and
* change the pointer in *save_rec to point to record_save_area.
* Saved_recno records the record number at the time of the save.
* This is used by annofile() to print the record number of a file's
* header record.
*/
static union record **saveRec;
static union record recordSaveArea;
static int savedRecno;
/*
* Record number of the start of this block of records
*/
static int baseRec;
/*
* Return the location of the next available input or output record.
*/
union record *
FindRec()
{
if (arRecord == arLast) {
if (FlushArchive())
return((union record *) nil);
if (arRecord == arLast)
return((union record *) nil); /* EOF */
}
return(arRecord);
}
/*
* Indicate that we have used all records up thru the argument.
* (should the arg have an off-by-1? XXX FIXME)
*/
void
UseRec(rec)
union record *rec;
{
while (rec >= arRecord)
arRecord++;
/*
* Do NOT flush the archive here. If we do, the same
* argument to userec() could mean the next record (if the
* input block is exactly one record long), which is not what
* is intended.
*/
if (arRecord > arLast) {
PgmAlert("\pUseRec", "\parRecord > arLast", nil);
return;
}
}
/*
* Return a pointer to the end of the current records buffer.
* All the space between findrec() and endofrecs() is available
* for filling with data, or taking data from.
*/
union record *
EndOfRecs()
{
return(arLast);
}
/*
* Open an archive file. The argument specifies whether we are
* reading or writing.
*/
Boolean
OpenArchive(read)
int read;
{
OSErr err;
char *routine = "\pOpenArchive";
HParamBlockRec hpb;
/*
* Get a block buffer for use later
*/
arBlock = (union record *) NewPtr((Size) blockSize);
if (arBlock == nil)
{
OSAlert(routine, "\pNewPtr", "\parBlock", MemError());
return(true);
}
arRecord = arBlock;
arLast = arBlock + blocking;
/*
* Try and open the archive file.
*/
hpb.ioParam.ioCompletion = 0;
hpb.ioParam.ioNamePtr = arName;
hpb.ioParam.ioVRefNum = arVRefNum;
hpb.fileParam.ioDirID = arDirID; /* HIOParam is broke on this field! */
hpb.ioParam.ioMisc = 0;
if (read)
{
hpb.ioParam.ioPermssn = fsRdPerm;
err = PBHOpen( &hpb, (Boolean)0 );
}
else
{
err = PBHCreate( &hpb, (Boolean)0 );
if ( (err == noErr) || (err == dupFNErr) )
{
hpb.fileParam.ioCompletion = 0;
hpb.fileParam.ioNamePtr = arName;
hpb.fileParam.ioVRefNum = arVRefNum;
hpb.fileParam.ioDirID = arDirID;
hpb.fileParam.ioFDirIndex = 0;
err = PBHGetFInfo( &hpb, (Boolean)0 );
if (err == noErr)
{
hpb.fileParam.ioCompletion = 0;
hpb.fileParam.ioNamePtr = arName;
hpb.fileParam.ioVRefNum = arVRefNum;
hpb.fileParam.ioDirID = arDirID;
hpb.fileParam.ioFDirIndex = 0;
hpb.fileParam.ioFlFndrInfo.fdType = (OSType)'TARF';
hpb.fileParam.ioFlFndrInfo.fdCreator = (OSType)APPL_TYPE;
err = PBHSetFInfo( &hpb, (Boolean)0 );
}
hpb.ioParam.ioCompletion = 0;
hpb.ioParam.ioNamePtr = arName;
hpb.ioParam.ioVRefNum = arVRefNum;
hpb.ioParam.ioPermssn = fsRdWrPerm;
hpb.fileParam.ioDirID = arDirID;
hpb.ioParam.ioMisc = 0;
err = PBHOpen( &hpb, (Boolean)0 );
}
}
if (err != noErr)
{
OSAlert(routine, "\pFSOpen or FSCreate", arName, err);
DisposPtr((Ptr) arBlock);
archive = 0;
return(true);
}
else
{
archive = hpb.ioParam.ioRefNum;
}
if (!read && ((err = SetEOF(archive, 0L)) != noErr)) {
OSAlert(routine, "\pSetEOF", arName, err);
DisposPtr((Ptr) arBlock);
archive = 0;
return(true);
}
arReading = read;
if (read) {
arLast = arBlock; /* Set up for 1st block = # 0 */
FlushArchive();
}
return(false);
}
/*
* Remember a union record * as pointing to something that we
* need to keep when reading onward in the file. Only one such
* thing can be remembered at once, and it only works when reading
* an archive.
*/
SaveRec(pointer)
union record **pointer;
{
saveRec = pointer;
savedRecno = baseRec + arRecord - arBlock;
}
/*
* Perform a write to flush the buffer.
*/
Boolean
FlWrite()
{
OSErr err;
long count;
count = blockSize;
err = FSWrite(archive, &count, arBlock->charptr);
if ((err == noErr) && (count == blockSize))
return(false);
if ((count != blockSize) || (err == dskFulErr))
DFAlert();
else
OSAlert("\pFLWrite", "\pFSWrite", "\pArchive write", err);
return(true);
}
/*
* Perform a read to flush the buffer.
*/
Boolean
FlRead()
{
OSErr err; /* Result from system call */
long count;
int left; /* Bytes left */
char *more; /* Pointer to next byte to read */
char *routine = "\pFlRead";
/*
* If we are about to wipe out a record that
* somebody needs to keep, copy it out to a holding
* area and adjust somebody's pointer to it.
*/
if (saveRec &&
*saveRec >= arRecord &&
*saveRec < arLast) {
recordSaveArea = **saveRec;
*saveRec = &recordSaveArea;
}
count = blockSize;
err = FSRead(archive, &count, arBlock->charptr);
if ((err == noErr) && (count == blockSize))
return(false);
else if ((err != noErr) && (err != eofErr)) {
OSAlert("\pReadError", "\pFSRead", "\pArchive read", err);
return(true);
}
more = arBlock->charptr + count;
left = blockSize - count;
again:
if (0 == (((unsigned)left) % RECORDSIZE)) {
/* FIXME, for size=0, multi vol support */
/* On the first block, warn about the problem */
if (!reblock && baseRec == 0) {
char buf[80];
sprintf(&buf[1], "Blocksize = %ld records",
count / (long) RECORDSIZE);
buf[0] = strlen(&buf[1]);
PgmAlert(routine, buf, nil);
}
arLast = arBlock + ((unsigned)(blockSize - left))/RECORDSIZE;
return(false);
}
if (reblock) {
/*
* User warned us about this. Fix up.
*/
if (left > 0) {
count = left;
err = FSRead(archive, &count, more);
if ((err != noErr) && (err != eofErr)) {
OSAlert("\pReadError", "\pFSRead",
"\pArchive read 2", err);
return(true);
}
if ((count == 0) || (err = eofErr)) {
PgmAlert(routine, "\pEof not on block boundary",
nil);
return(true);
}
left -= count;
more += count;
goto again;
}
} else {
PgmAlert(routine, "\pDid not read blocksize bytes", nil);
return(true);
}
}
/*
* Flush the current buffer to/from the archive.
*/
Boolean
FlushArchive()
{
baseRec += arLast - arBlock;/* Keep track of block #s */
arRecord = arBlock; /* Restore pointer to start */
arLast = arBlock + blocking; /* Restore pointer to end */
if (!arReading)
return(FlWrite());
else
return(FlRead());
}
/*
* Close the archive file.
*/
CloseArchive()
{
if (!arReading)
(void) FlushArchive();
DisposPtr((Ptr) arBlock);
if (archive != 0)
(void) FSClose(archive);
archive = 0;
}
#ifdef NEVER_DEFINED
/*
* bcopy and bzero compatability routines.
* These could (should) potentially be done with the Mac traps.
*/
char *
bcopy(s1, s2, n)
char *s1, *s2;
register int n;
{
register char *s = s1;
register char *d = s2;
while (--n >= 0)
*d++ = *s++;
return(s1);
}
#endif
#ifndef THINK_C
void
bzero (s1, n)
register char *s1;
register int n;
{
while (--n >= 0)
*s1++ = 0;
}
#endif